package tcp

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/GoDistributedCacheFramework/src/cache"
	"github.com/GoDistributedCacheFramework/src/cluster"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
)

type Server struct {
	cache.Cache	// 缓存
	cluster.Node	// 节点
}

// TCP 开启监听
func (s *Server) Listen()  {
	l,e := net.Listen("tcp",s.Addr() + ":12346")
	if e != nil {
		panic(e)
	}
	// 无限循环接受客户端请求
	for {
		c,e := l.Accept()
		if e != nil {
			panic(e)
		}
		// 处理监听到的请求
		go s.processs(c)
	}
}

func New(c cache.Cache,n cluster.Node) *Server  {
	return &Server{c,n}
}

// key 值读取
func (s *Server) readKey (r *bufio.Reader) (string,error)  {
	klen,e := readLen(r)
	if e != nil {
		return "",e
	}
	k := make([]byte,klen)
	_,e = io.ReadFull(r,k)
	if e != nil {
		return "",e
	}
	key := string(k)
	addr,ok := s.ShouldProcess(key)
	if !ok {
		return "",errors.New("redirect "+ addr)
	}
	return key,nil

}

// 获取key，value
func (s *Server) readKeyAndValue (r *bufio.Reader) (string,[]byte,error)  {
	klen,e := readLen(r)
	if e != nil {
		return "",nil,e
	}
	vlen,e := readLen(r)
	if e != nil {
		return "",nil,e
	}
	k := make([]byte,klen)
	_,e = io.ReadFull(r,k)
	if e != nil {
		return "",nil,e
	}
	key := string(k)
	addr,ok := s.ShouldProcess(key)
	if !ok {
		return "",nil,errors.New("redirect "+addr)
	}
	v := make([]byte,vlen)
	_,e = io.ReadFull(r,v)
	if e != nil {
		return "",nil,e
	}
	return key,v,nil
}

// 以空格为分隔符读取一个字符串并将其转化为一个整型
func readLen(r *bufio.Reader) (int,error)  {
	tmp,e := r.ReadString(' ')
	if e != nil {
		return 0,e
	}
	l,e := strconv.Atoi(strings.TrimSpace(tmp))
	if e != nil {
		return 0,e
	}
	return l,nil

}

// 根据参数将服务段的error或value写入客户端连接
func sendRespose(value []byte,err error,conn net.Conn) error {
	if err != nil {
		errString := err.Error()
		tmp := fmt.Sprintf("-%d",len(errString)) + errString
		_,e := conn.Write([]byte(tmp))
		return e
	}
	vlen := fmt.Sprintf("%d",len(value))
	_,e := conn.Write(append([]byte(vlen),value...))
	return e

}

// 从command中获取value,然后将value写入客户端连接
func (s *Server) get(conn net.Conn,r *bufio.Reader) error  {
	k,e := s.readKey(r)
	if e != nil {
		return e
	}
	v,e := s.Get(k)

	return sendRespose(v,e,conn)


}

func (s *Server) set(conn net.Conn,r *bufio.Reader) error  {
	k,v,e := s.readKeyAndValue(r)
	if e != nil {
		return e
	}
	return sendRespose(nil,s.Set(k,v),conn)
}

func (s *Server) del (conn net.Conn,r *bufio.Reader) error  {
	k,e := s.readKey(r)
	if e != nil {
		return e
	}
	return sendRespose(nil,s.Del(k),conn)
}

// 监听到的请求处理
func (s *Server) process(conn net.Conn)  {
	defer conn.Close()
	r := bufio.NewReader(conn)
	for {
		// 读取请求
		op,e := r.ReadByte()
		if e != nil {
			if e != io.EOF {
				log.Println("close connection due to server:",e)
			}
			return
		}
		if op == 'S' {	// 请求为 set，新建 kv
			e = s.set(conn,r)
		} else  if op == 'G' {	// 请求为 get，获取 kv
			e = s.get(conn,r)
		} else if op == 'D' {	// 请求为 delete，删除 kv
			e = s.del(conn,r)
		} else {
			log.Println("close connection due to invalid operation:",op)
			return
		}
		if e != nil {
			log.Println("close connection due to error process:",e)
			return
		}
	}

}

// 异步操作
type result struct {
	v []byte
	e error
}

func (s *Server) processs(conn net.Conn)  {
	r := bufio.NewReader(conn)
	resultCh := make(chan chan *result,5000)
	defer close(resultCh)
	go reply(conn,resultCh)
	for {
		op,e := r.ReadByte()
		if e != nil {
			if e != io.EOF {
				log.Println("close connection due to error processs:",e)
			}
			return
		}
		if op == 'S' {
			s.sets(resultCh,r)
		} else if op == 'G' {
			s.gets(resultCh,r)
		} else if op == 'D' {
			s.dels(resultCh,r)
		} else {
			log.Println("close connection due to invalid operation:",op)
			return
		}
	}
}

func reply(conn net.Conn,resultCh chan chan *result)  {
	defer conn.Close()
	for {
		c,open := <-resultCh
		if !open {
			return
		}
		r := <-c
		e := sendRespose(r.v,r.e,conn)
		if e != nil {
			log.Println("close connection due to error reply:",e)
			return
		}
	}
}

// 缓存操作函数
func (s *Server) gets(ch chan chan *result,r *bufio.Reader)  {
	c := make(chan *result)
	ch <- c
	k,e := s.readKey(r)
	if e != nil {
		c <- &result{nil,e}
		return
	}
	go func() {
		v,e := s.Get(k)
		c <- &result{v,e}
	}()
}

func (s *Server) sets(ch chan chan *result,r *bufio.Reader)  {
	c := make(chan *result)
	ch <- c
	k,v,e := s.readKeyAndValue(r)
	if e != nil {
		c <- &result{nil,e}
		return
	}
	go func() {
		c <- &result{nil,s.Set(k,v)}
	}()
}

func (s *Server) dels(ch chan chan *result,r *bufio.Reader)  {
	c := make(chan *result)
	ch <- c
	k,e := s.readKey(r)
	if e != nil {
		c <- &result{nil,e}
		return
	}
	go func() {
		c <- &result{nil,s.Del(k)}
	}()
}

